# Импорт библиотек
import pandas as pd
import numpy as np
import random
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as st
import scipy as sp
pd.options.mode.chained_assignment = None # default='warn
Важно определить, какие технические показатели качества связи сильнее всего влияют на удовлетворённость клиентов, и в первую очередь направить ресурсы на работу с ними.
data = pd.read_csv('megafon.csv') # Загрузка данных
data.head(3) # Cтруктура данных
| user_id | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming Download Throughput(Kbps) | Video Streaming xKB Start Delay(ms) | Web Page Download Throughput(Kbps) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 5 | NaN | 775.48846 | 360.13 | 86.56 | 3.93 | 1859.15 | 2309 | 1007.82 | 83 |
| 1 | 2 | 5 | 4 | 861.96324 | 3023.54 | 411.18 | 1.27 | 667.47 | 2080 | 255.36 | 425 |
| 2 | 3 | 1 | 4 | 261.11860 | 790.96 | 34.20 | 1.79 | 1079.60 | 6367 | 535.85 | 485 |
user_id — идентификатор абонента;
Q1 — ответ на первый вопрос В ходе опроса компания «Мегафон» предложила своим клиентам оценить уровень удовлетворённости качеством связи по десятибалльной шкале (где 10 — это «отлично», а 1 — «ужасно»). Если клиент оценивал качество связи на 9 или 10 баллов, опрос заканчивался;
Q2 - ответ на второй вопрос ; Если клиент ставил оценку ниже 9, задавался второй вопрос — о причинах неудовлетворённости качеством связи с предоставленными пронумерованными вариантами ответа. Ответ можно было дать в свободном формате или перечислить номера ответов через запятую:
Total Traffic(MB) — объем трафика передачи данных, насколько активно абонент использует мобильный интернет;
Downlink Throughput(Kbps) — средняя скорость «к абоненту», считается по всему трафику передачи данных;
Uplink Throughput(Kbps)— средняя скорость «от абонента», считается по всему трафику передачи данных;
Downlink TCP Retransmission Rate(%) — частота переотправок пакетов «к абоненту», чем выше, тем хуже. Если в канале возникает ошибка, пакет переотправляется. Снижается полезная скорость;
Video Streaming Download Throughput(Kbps) — скорость загрузки потокового видео, чем выше, тем лучше — меньше прерываний и лучше качество картинки;
Video Streaming xKB Start Delay(ms) — задержка старта воспроизведения видео, cколько времени пройдёт между нажатием на кнопку Play и началом воспроизведения видео. Чем меньше это время, тем быстрее начинается воспроизведение;
Web Page Download Throughput(Kbps) — скорость загрузки web-страниц через браузер, чем выше, тем лучше;
Web Average TCP RTT(ms) — пинг при просмотре web-страниц, чем меньше, тем лучше — быстрее загружаются web-страницы.
Первый технический показатель представлен как сумма за период в одну неделю перед участием в опросе. Остальные технические показатели отображают среднее значение по данному признаку за период в одну неделю перед участием в опросе.
data.info() # Непустые значения в колонках
<class 'pandas.core.frame.DataFrame'> RangeIndex: 3112 entries, 0 to 3111 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 user_id 3112 non-null int64 1 Q1 3110 non-null object 2 Q2 1315 non-null object 3 Total Traffic(MB) 3112 non-null float64 4 Downlink Throughput(Kbps) 3112 non-null float64 5 Uplink Throughput(Kbps) 3112 non-null float64 6 Downlink TCP Retransmission Rate(%) 3112 non-null float64 7 Video Streaming Download Throughput(Kbps) 3112 non-null float64 8 Video Streaming xKB Start Delay(ms) 3112 non-null int64 9 Web Page Download Throughput(Kbps) 3112 non-null float64 10 Web Average TCP RTT(ms) 3112 non-null int64 dtypes: float64(6), int64(3), object(2) memory usage: 267.6+ KB
Работа с переменной Q1 - ответ на первый вопрос, возможные значения 1-10
data['Q1'].value_counts() # Имеющиеся значения и их количество
10 846 1 532 3 325 8 291 9 238 5 234 7 200 2 168 4 123 6 101 0 10 Нет 2 5, 6 2 Да 2 1, 3 2 Пока не понял 1 Немагу дать атценку денги незашто снимаеть скоро выклучаю 1 Без з 1 Очень хорошо. Обслуживания я довольно. Спасибо вам.555 1 3 - дер.Ширяево Волоколамского района, 9 - в Москве 1 1, 6 1 10, 5 1 4. Тульская область Заокский район. Романовские дачи связи почти нет 1 3, 9 1 20, 89031081392 1 3 тройка, связь отвратительная, жалко платить за такой тарив 1 10, 50 1 3, 7 1 Я в Смол. Области живу сейчас, не пользуюсь телефоном совсем 1 ? 1 2, 5 1 2, 9 1 Отвратительно 1 0, 1, 5 1 Когда в Москве-10 а когда в калужской области в деревне Бели-1 1 Чем даль ше,тем лучше.Спасибо за ваш труд.Оценка 10 ! 1 1, 8 1 Ужасно 1 Hi 1 Чдтчдтччдтччч 1 10, 9 1 19 1 ***** ** *** 1 11 1 Поохое 1 ОЦЕНКА-3/НЕВАЖНО/ 1 15 1 5, 7 1 Я ценой услуг не удовлетворен 1 Name: Q1, dtype: int64
data['user_id'] = data['user_id'].astype(str) # Удалим ошибочные и пропущенные значения с ответом на первый вопрос
data['Q1'] = data['Q1'].astype('str')
data['Q1'] = [elem if elem in ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
else np.NaN for elem in data['Q1']]
data.dropna(subset=['Q1'], inplace=True)
data['Q1'].value_counts()
10 846 1 532 3 325 8 291 9 238 5 234 7 200 2 168 4 123 6 101 Name: Q1, dtype: int64
Разделим абонентов на группы и создадим метки группы для всех абонентов - A: оценка (9-10), B: оценка (5-8), C: оценка (1-4)
data['Group'] = data['Q1']
data['Group'] = ['A' if elem in ['9', '10'] else 'B' if elem
in ['5', '6', '7', '8'] else 'C' for elem in data['Group']]
data['Group'].value_counts() # Количество абонентов по группам
C 1148 A 1084 B 826 Name: Group, dtype: int64
# Изменим порядок колонок в датасете
cols = ['user_id', 'Group', 'Q1', 'Q2', 'Total Traffic(MB)',
'Downlink Throughput(Kbps)', 'Uplink Throughput(Kbps)',
'Video Streaming Download Throughput(Kbps)', 'Web Page Download Throughput(Kbps)',
'Downlink TCP Retransmission Rate(%)', 'Video Streaming xKB Start Delay(ms)',
'Web Average TCP RTT(ms)']
data = data[cols]
data.head(1)
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | B | 5 | NaN | 775.48846 | 360.13 | 86.56 | 1859.15 | 1007.82 | 3.93 | 2309 | 83 |
# Т.к. отсутствующие значения остались только в колонке Q2, проставим ответ 6 (затрудняюсь ответить) для пустых значений
data.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 3058 entries, 0 to 3111 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 user_id 3058 non-null object 1 Group 3058 non-null object 2 Q1 3058 non-null object 3 Q2 1315 non-null object 4 Total Traffic(MB) 3058 non-null float64 5 Downlink Throughput(Kbps) 3058 non-null float64 6 Uplink Throughput(Kbps) 3058 non-null float64 7 Video Streaming Download Throughput(Kbps) 3058 non-null float64 8 Web Page Download Throughput(Kbps) 3058 non-null float64 9 Downlink TCP Retransmission Rate(%) 3058 non-null float64 10 Video Streaming xKB Start Delay(ms) 3058 non-null int64 11 Web Average TCP RTT(ms) 3058 non-null int64 dtypes: float64(6), int64(2), object(4) memory usage: 310.6+ KB
data[data['Group'] != 'A'] = data[data['Group'] != 'A'].fillna('6')
data[(data['Q1'] == '9') | (data['Q1'] == '10')][['Q2']].shape[0] # Проверим количество строк группы A
1084
data[(data['Q1'] == '9') | (data['Q1'] == '10')][['Q2']].isna().sum()[0]
# Проверим пустые значения группы A на Q2 - совпадает
1084
data_Q1 = data.copy()
Построение доверительных интервалов для оценки долей пользователей, которые полностью довольны качеством связи (группа A), и для пользователей, которые неудовлетворёны качеством связи (группы В и С)
Оценка данного показателя позволяет оценить общую картину удовлетворенности услугами компании "Мегафон" с целью дальнейшего анализа конкретных групп и показателей
data_Q1[['user_id']].duplicated().sum() # Количество повторяющихся пользователей
0
df1 = data_Q1.copy()
df1['Group'] = ['Satisfied' if elem == 'A' else 'Dissatisfied' for elem in df1['Group']]
df1 = df1.groupby(['Group'])[['user_id']].count()
px.bar(df1, color=df1.index,
title='Количество пользователей в группах удовлетворенности услугами')
Расчет доверительного интервала для доли пользователей полностью удовлетворенными качеством связи (Ответ 9,10 на первый вопрос) генеральной совокупности пользователей компании 'Мегафон'
n = data_Q1.shape[0] # Размер выборки
n
3058
p = data_Q1[data_Q1['Group'] == 'A'].shape[0] / n
se = np.sqrt(p * (1 - p) / n)
np.round(st.norm.interval(0.95, loc=p, scale=se), 4)
array([0.3375, 0.3714])
Расчет доверительного интервала для доли пользователей неудовлетворенными качеством связи (Ответ 1-8 на первый вопрос) генеральной совокупности пользователей компании 'Мегафон'
n = data_Q1.shape[0]
p = data_Q1[data_Q1['Group'] != 'A'].shape[0] / n
se = np.sqrt(p * (1 - p) / n)
np.round(st.norm.interval(0.95, loc=p, scale=se), 4)
array([0.6286, 0.6625])
С вероятностью в 95% доля пользователей полностью удовлетворенными качеством связи компании 'Мегафон' лежит в промежутке (0.3375; 0.3714), доля пользоваталей неудовлетворенными качеством связи лежит в промежутке (0.6286; 0.6625)
Можем сделать вывод, что примерно 2/3 пользователей имеют некоторые проблемы со связью, следовательно нужно подробнее разбирать группы пользователей B и C
Построение доверительного интервала для оценки доли пользователей, которые указали на проблемы по связью (ответы: 1,2,3; на второй вопрос), относительно всех пользователей
Рассмотрение данного показателя в первую очередь важно, т.к. компания специализуруется на услугах голосовой связи и большинство пользователей указали на проблему именно с данной составляющей бизнеса
# Cоздание массива, разделенного по Q2, с наличием выбросов в числовых признаках для расчета доли
df2 = data_Q1.copy()
# Разделение нескольких ответов на список ответов
df2['Q2'] = df2['Q2'].str.replace(" ", "").str.split(',')
df2 = df2.explode('Q2') # Q2 - ответ на первый вопрос, возможные значения 1-7, или несколько ответов
df2['Q2'] = [elem if elem in ['1', '2', '3', '4', '5', '6', '7', np.NaN]
else 'error' for elem in df2['Q2']]
df2 = df2[df2['Q2'] != 'error']
# Заполним пропуски в Q2 для групп B и C нейтральным ответов
df2[df2['Group'] != 'A'] = df2[df2['Group'] != 'A'].fillna('6')
df2 = df2.reset_index(drop=True)
df2_1 = df2[(df2['Q2'] == '1') | (df2['Q2'] == '2') | (df2['Q2'] == '3')] # Интересующие нас группы
df2_1 = df2_1.drop_duplicates(subset='user_id') # Устранение повторяющихся пользователей внутри групп
df2_1
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | 4 | B | 8 | 3 | 179.18564 | 2590.97 | 325.88 | 7053.81 | 1221.02 | 0.80 | 3218 | 51 |
| 4 | 5 | C | 2 | 2 | 351.99208 | 731.61 | 223.54 | 4550.38 | 2336.56 | 1.15 | 1767 | 68 |
| 11 | 9 | C | 1 | 1 | 783.64464 | 1786.99 | 271.77 | 6802.42 | 1837.02 | 0.84 | 1200 | 132 |
| 14 | 10 | C | 3 | 1 | 455.97369 | 610.43 | 81.86 | 1317.76 | 1054.15 | 4.10 | 3350 | 165 |
| 18 | 11 | C | 3 | 1 | 526.08652 | 535.54 | 208.67 | 2621.14 | 2376.50 | 1.46 | 1479 | 88 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 4206 | 3103 | B | 8 | 1 | 413.99008 | 908.59 | 215.83 | 9449.73 | 2212.11 | 1.62 | 1467 | 51 |
| 4208 | 3105 | C | 1 | 1 | 206.28181 | 105.24 | 65.84 | 349.04 | 1035.69 | 3.86 | 2094 | 267 |
| 4213 | 3108 | C | 3 | 1 | 519.96475 | 1045.70 | 44.61 | 4523.66 | 1044.66 | 0.47 | 1468 | 304 |
| 4216 | 3109 | C | 3 | 1 | 171.52629 | 670.32 | 40.94 | 1711.54 | 954.91 | 2.35 | 2780 | 251 |
| 4221 | 3111 | B | 6 | 1 | 827.74515 | 1841.90 | 373.53 | 5675.93 | 2361.88 | 1.21 | 1905 | 202 |
1028 rows × 12 columns
n = data_Q1.shape[0] # Размер выборки
n
3058
p = df2_1.shape[0] / n
se = np.sqrt(p * (1 - p) / n)
np.round(st.norm.interval(0.95, loc=p, scale=se), 4)
array([0.3194, 0.3529])
С вероятностью в 95% доля пользователей, которые указали на проблемы по связью (ответы: 1,2,3; на второй вопрос), относительно всех пользователей компании 'Мегафон' лежит в промежутке (0.3194, 0.3529])
# for i in ['1', '2', '3', '4', '5', '6', '7']:
# df_inter = df2[(df2['Q2'] == i)]
# df_inter = df_inter.drop_duplicates(subset='user_id')
# p = df_inter.shape[0] / n
# se = np.sqrt(p * (1 - p) / n)
# print('Доверительный интервал для доли пользователей, ответивших на Q2 -', i,
# np.round(st.norm.interval(0.95, loc=p, scale=se), 4))
Устранение выбросов в числовых признаках
Следуя эвристики, что выбросы находятся за пределами следующих интервалов: Q1–1.5 x IQR и Q3 + 1.5 x IQR, преобразуем данные.
Q1 - Первый квартиль, равен 25-ому процентилю;
Q3 - Третий квартиль, равен 75-ому процентилю;
IQR - число, которое показывает разброс средней половины (т.е. средние 50%) набора данных и помогает определить выбросы, разница между Q3 и Q1;
col = data.describe().columns # Колонки числовых атрибутов
Q1, Q3 = data_Q1[col].quantile(0.25), data_Q1[col].quantile(0.75)
IQR = Q3 - Q1
data_Q1_Out = data_Q1[~((data_Q1[col] < (Q1 - 1.5 * IQR)) | (data_Q1[col] >
(Q3 + 1.5 * IQR))).any(axis=1)]
data = data_Q1_Out
Работа с переменной Q2 - ответ на первый вопрос, возможные значения 1-7, или несколько ответов
data.Q2.isna().sum()
700
data['Q2'].value_counts()
6 451 3 135 4 100 1 98 1, 3 80 3, 4 65 1, 3, 4 43 7 39 1, 2, 3 31 1, 4 29 1, 3, 4, 5 28 3, 4, 5 27 1, 2, 3, 4, 5 19 1, 2 16 4, 5 16 1, 2, 3, 4 13 1, 4, 5 13 2, 3 7 1, 2, 4 7 2, 3, 4 7 3, 5 7 2 6 1, 5 5 5 4 1, 3, 5 3 2, 3, 4, 5 3 2, 4 3 1, 4, 7 3 2, 4, 5 2 1, 2, 5 2 1, 3, 4, 7 2 1, 3, 4, 5, 7 2 1, 2, 4, 5 2 1, 3, 7 1 0, 1, 7 1 1, 2, 7 1 1, 2, 3, 7 1 0 1 3, 4, 5, 7 1 0, 3 1 0, 05, 2, 27, 7 1 1, 2, 34 1 1, 2, 3, 4, 5, 6 1 1, 2, 3, 5 1 3, 4, 7 1 3, 7 1 Name: Q2, dtype: int64
# Для наблюдений с несколькими вариантами, уберем пробелы, переведем в списки и разобьем на отдельные наблюдения.
# Значения остальных атрибутов для таких наблюдений остаются неизменными.
data['Q2'] = data['Q2'].str.replace(" ", "").str.split(',')
data = data.explode('Q2')
data['Q2'] = [elem if elem in ['1', '2', '3', '4', '5', '6', '7', np.NaN]
else 'error' for elem in data['Q2']]
data = data[data['Q2'] != 'error']
data['Q2'].value_counts() #Финальное количество вариантов ответа на Q2
3 480 6 452 1 403 4 387 5 136 2 124 7 54 Name: Q2, dtype: int64
# Заполним пропуски в Q2 для групп B и C нейтральным ответов
data[data['Group'] != 'A'] = data[data['Group'] != 'A'].fillna('6')
data = data.reset_index(drop=True)
data_Q2 = data.copy()
Рассмотрим данные для минимальных и максимальных показателей каждого признака с соответствующими значениями других признаков
datamin = pd.DataFrame(columns=data.columns)
datamax = pd.DataFrame(columns=data.columns)
# Создадим копию данных и исключим ошибочные минимальные (нулевые) значения признаков
data_copy = data.copy()
data_copy = data_copy[(data_copy['Video Streaming Download Throughput(Kbps)'] > 0) &
(data_copy['Web Page Download Throughput(Kbps)'] > 0) &
(data_copy['Web Average TCP RTT(ms)'] > 0)]
for column in data[col]:
datamin = datamin.append(data_copy[data_copy[column] == data_copy[column].min()])
datamax = datamax.append(data_copy[data_copy[column] == data_copy[column].max()])
# Исключим дубликаты из полученных датафреймов
datamin = datamin.drop_duplicates(subset='Total Traffic(MB)')
datamax = datamax.drop_duplicates(subset='Total Traffic(MB)')
# datamin.append(data_Q1_Out.describe().loc[['mean'], :], sort=False)
# datamax.append(data_Q1_Out.describe().loc[['mean'], :], sort=False)
Рассмотрим меры центральной тенденции - среднее и медиану для групп пользователей разделенных по ответу на первый вопрос:
Группы - A: оценка (9-10), B: оценка (5-8), C: оценка (1-4)
Q1_mean_1 = data_Q1_Out.groupby(['Group'])[['user_id']].count()
Q1_mean_1.columns = ['user_id, count']
Q1_mean_2 = data_Q1_Out.groupby(['Group']).agg('mean') \
.sort_values(by='Group').round(2)
Q1_mean = pd.concat([Q1_mean_1, Q1_mean_2], axis=1)
Q1_median_1 = data_Q1_Out.groupby(['Group'])[['user_id']].count()
Q1_median_1.columns = ['user_id, count']
Q1_median_2 = data_Q1_Out.groupby(['Group']).agg('median') \
.sort_values(by='Group').round(2)
Q1_median = pd.concat([Q1_median_1, Q1_median_2], axis=1)
Q1_mean # Средние для числовых показателей
| user_id, count | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|
| Group | |||||||||
| A | 700 | 412.30 | 1876.49 | 145.13 | 5371.52 | 1879.51 | 1.38 | 1696.58 | 131.57 |
| B | 547 | 424.04 | 1842.24 | 144.26 | 5260.61 | 1824.31 | 1.49 | 1768.55 | 138.85 |
| C | 734 | 416.21 | 1662.22 | 137.44 | 4708.80 | 1707.93 | 1.58 | 1855.18 | 149.55 |
Q1_median # Медианные значения для числовых показателей
| user_id, count | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|
| Group | |||||||||
| A | 700 | 365.00 | 1519.74 | 120.80 | 4821.22 | 1769.54 | 1.20 | 1572.5 | 105.5 |
| B | 547 | 389.35 | 1366.61 | 119.43 | 4623.44 | 1666.18 | 1.28 | 1655.0 | 114.0 |
| C | 734 | 377.32 | 1293.52 | 116.33 | 4109.82 | 1576.06 | 1.32 | 1694.0 | 127.5 |
Показатели: Total Traffic(MB) - из опрошенных мобильный интернет активнее всего используется пользователями группы 'B';
Downlink Throughput(Kbps),Uplink Throughput(Kbps), Video Streaming Download Throughput(Kbps), Web Page Download Throughput(Kbps) - наибольшие показатели скорости загрузки у пользователей группы 'A', наименьшие у группы 'C';
Downlink TCP Retransmission Rate(%)(частота переотправок пакетов «к абоненту»),Video Streaming xKB Start Delay(ms)(задержка старта воспроизведения видео),Web Average TCP RTT(ms)(пинг при просмотре web-страниц) - наименьшие (наилучшие) показатели у пользователей группы 'A', наибольшие (наихудшие) - у группы 'C';
В целом, основываясь на рассмотренных выборках, имеется предположение, что разница в показателях пользователей группы 'A' и группы 'B' различаются меньше, чем разница в показателях группы 'B' и 'C'.
Рассмотрим меры центральной тенденции - среднее и медиану для групп пользователей разделенных по ответу на второй вопрос:
1.Недозвоны, обрывы при звонках
2.Время ожидания гудков при звонке
3.Плохое качество связи в зданиях, тц и т.д.
4.Медленный мобильный интернет
5.Медленная загрузка видео
6.Затрудняюсь ответить
7.Свой вариант
Q2_mean_1 = data_Q2.groupby(['Q2'])[['user_id']].count()
Q2_mean_1.columns = ['user_id, count']
Q2_mean_2 = data_Q2.groupby(['Q2']).agg('mean') \
.sort_values(by='Q2').round(2)
Q2_mean = pd.concat([Q2_mean_1, Q2_mean_2], axis=1)
Q2_median_1 = data_Q2.groupby(['Q2'])[['user_id']].count()
Q2_median_1.columns = ['user_id, count']
Q2_median_2 = data_Q2.groupby(['Q2']).agg('median').sort_values(by='Q2').round(2)
Q2_median = pd.concat([Q2_median_1, Q2_median_2], axis=1)
Q2_mean # Средние для числовых показателей
| user_id, count | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|
| Q2 | |||||||||
| 1 | 403 | 410.06 | 1787.28 | 145.94 | 5045.35 | 1756.82 | 1.59 | 1817.25 | 145.68 |
| 2 | 124 | 395.59 | 1654.47 | 140.41 | 4793.18 | 1770.88 | 1.56 | 1847.86 | 153.37 |
| 3 | 480 | 420.52 | 1728.35 | 141.19 | 4817.77 | 1769.04 | 1.62 | 1809.03 | 142.59 |
| 4 | 387 | 440.76 | 1661.62 | 135.53 | 4482.69 | 1648.09 | 1.59 | 1902.98 | 154.15 |
| 5 | 136 | 434.34 | 1447.95 | 131.38 | 3919.86 | 1613.10 | 1.58 | 1929.76 | 157.15 |
| 6 | 452 | 412.84 | 1684.16 | 142.23 | 5047.90 | 1769.47 | 1.50 | 1796.79 | 146.30 |
| 7 | 54 | 406.87 | 1753.45 | 138.13 | 4808.98 | 1803.71 | 1.52 | 1817.15 | 131.33 |
Q2_median # Медианные значения для числовых показателей
| user_id, count | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|
| Q2 | |||||||||
| 1 | 403 | 370.92 | 1361.30 | 119.45 | 4576.39 | 1589.45 | 1.37 | 1662.0 | 125.0 |
| 2 | 124 | 375.97 | 1095.54 | 116.10 | 4050.38 | 1628.90 | 1.32 | 1709.5 | 131.5 |
| 3 | 480 | 379.86 | 1314.74 | 121.15 | 4252.07 | 1644.94 | 1.34 | 1664.5 | 117.0 |
| 4 | 387 | 415.86 | 1155.32 | 118.53 | 3915.89 | 1498.28 | 1.36 | 1743.0 | 133.0 |
| 5 | 136 | 413.47 | 1108.19 | 104.55 | 3287.10 | 1430.19 | 1.33 | 1743.5 | 135.5 |
| 6 | 452 | 366.52 | 1265.22 | 116.13 | 4349.46 | 1641.42 | 1.27 | 1671.0 | 122.0 |
| 7 | 54 | 352.47 | 1543.91 | 124.46 | 4223.85 | 1513.76 | 1.39 | 1700.5 | 101.0 |
На первый взгляд - видимых различий не наблюдается, более детальные различия и гипотезы между данными группами далее будут проверены в ходе исследования
Тесты по качеству голосовой связи фиксируют следующие параметры:
Качество голосовой связи. Включает в себя долю неуспешных попыток установления соединения, долю оборванных вызовов, разборчивость речи. Качество речи измеряется по технологии POLQA (Perceptual Objective Listening Quality Assessment), утверждённой Международным союзом электросвязи. Оценка каждого голосового вызова осуществляется на протяжении трех минут. Результатом обзвона «большой четверки» является совокупность log-файлов измерительных комплексов. Оценка каждого голосового вызова осуществляется на протяжении 3 минут.
Доставку sms-сообщений (доля недошедших до адресата сообщений, а также среднее время доставки).
Передачу данных: доля неуспешного TCP/IP соединения с сервером (HTTP IP-Service Access Failure Ratio); доля неуспешных сессий по протоколу HTTP (HTTP Session Failure Ratio); среднее значение скорости передачи данных к абоненту (HTTP DL Mean User Data Rate) в кбит/c; продолжительность успешной сессии (HTTP Session Time) в мс. Процедура выполняется для трёх стандартов: GSM (2G), UMTS (3G) и LTE (4G). Размер файла для загрузки по протоколу HTTP для GSM и UMTS составляет 3 МБ, а для LTE 100 МБ.
Общий скан покрытия, наличие и уровень сигнала (измеряемый в дБм).
Параметры, выделенные жирным шрифтом, имеются в представленных данных, следуют обратить на них внимание при исследованиее пользователей имеющих проблемы со связью (1.Недозвоны, обрывы при звонках; 2.Время ожидания гудков при звонке; 3.Плохое качество связи в зданиях, тц и т.д.)
Проверяем гипотезу относительно разницы средних показателей Downlink Throughput(Kbps)(средняя скорость «к абоненту»),Downlink TCP Retransmission Rate(%) (частота переотправок пакетов «к абоненту», чем выше, тем хуже.) между группами пользоваталей A и B
Группа A - пользователи, ответившие на второй вопрос (Q2) - 1,2,3: 1. Недозвоны, обрывы при звонках; 2. Время ожидания гудков при звонке; 3. Плохое качество связи в зданиях, тц и т.д Группа B - пользователи, ответившие на первый вопрос (Q1) - 9, 10 (отличное качество связи)
Берем наши выборки, делаем по каждой из них бутстреп и проверяем с помощью построения доверительных интервалов, пересекаются ли они, а также генерируем распределние разницы средних.
# Группа A
df2_2 = df2[(df2['Q2'] == '1') | (df2['Q2'] == '2') | (df2['Q2'] == '3')] # Интересующие нас пользователи
df2_2 = df2_1.drop_duplicates(subset='user_id') # Устранение повторяющихся пользователей внутри групп
df2_2
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | 4 | B | 8 | 3 | 179.18564 | 2590.97 | 325.88 | 7053.81 | 1221.02 | 0.80 | 3218 | 51 |
| 4 | 5 | C | 2 | 2 | 351.99208 | 731.61 | 223.54 | 4550.38 | 2336.56 | 1.15 | 1767 | 68 |
| 11 | 9 | C | 1 | 1 | 783.64464 | 1786.99 | 271.77 | 6802.42 | 1837.02 | 0.84 | 1200 | 132 |
| 14 | 10 | C | 3 | 1 | 455.97369 | 610.43 | 81.86 | 1317.76 | 1054.15 | 4.10 | 3350 | 165 |
| 18 | 11 | C | 3 | 1 | 526.08652 | 535.54 | 208.67 | 2621.14 | 2376.50 | 1.46 | 1479 | 88 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 4206 | 3103 | B | 8 | 1 | 413.99008 | 908.59 | 215.83 | 9449.73 | 2212.11 | 1.62 | 1467 | 51 |
| 4208 | 3105 | C | 1 | 1 | 206.28181 | 105.24 | 65.84 | 349.04 | 1035.69 | 3.86 | 2094 | 267 |
| 4213 | 3108 | C | 3 | 1 | 519.96475 | 1045.70 | 44.61 | 4523.66 | 1044.66 | 0.47 | 1468 | 304 |
| 4216 | 3109 | C | 3 | 1 | 171.52629 | 670.32 | 40.94 | 1711.54 | 954.91 | 2.35 | 2780 | 251 |
| 4221 | 3111 | B | 6 | 1 | 827.74515 | 1841.90 | 373.53 | 5675.93 | 2361.88 | 1.21 | 1905 | 202 |
1028 rows × 12 columns
# Группа B
df2_3 = data_Q1_Out[data_Q1_Out['Group'] == 'A']
df2_3 = df2_3.drop_duplicates(subset='user_id') # Устранение повторяющихся пользователей внутри групп
df2_3
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 15 | 16 | A | 10 | NaN | 767.54725 | 1729.37 | 107.94 | 2490.93 | 2514.08 | 1.96 | 1660 | 92 |
| 21 | 22 | A | 10 | NaN | 601.06519 | 2135.92 | 120.55 | 7215.26 | 1014.48 | 1.73 | 1649 | 231 |
| 25 | 26 | A | 10 | NaN | 360.59845 | 3743.08 | 250.93 | 5943.66 | 2714.29 | 0.98 | 2029 | 61 |
| 27 | 28 | A | 10 | NaN | 373.37642 | 865.79 | 82.03 | 1913.33 | 1743.42 | 2.62 | 2638 | 122 |
| 28 | 29 | A | 10 | NaN | 232.99499 | 535.05 | 71.64 | 1332.35 | 3421.72 | 1.07 | 3548 | 110 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 3091 | 3092 | A | 9 | NaN | 335.35499 | 1767.76 | 104.68 | 10115.44 | 462.42 | 0.38 | 1234 | 164 |
| 3092 | 3093 | A | 10 | NaN | 758.71809 | 1512.61 | 192.21 | 796.91 | 216.96 | 0.87 | 2567 | 160 |
| 3098 | 3099 | A | 10 | NaN | 343.79289 | 3469.50 | 237.13 | 4559.33 | 409.40 | 0.69 | 1725 | 150 |
| 3105 | 3106 | A | 10 | NaN | 424.34855 | 2258.16 | 150.21 | 5623.82 | 3480.14 | 1.56 | 1313 | 109 |
| 3109 | 3110 | A | 10 | NaN | 187.44936 | 590.29 | 186.36 | 3182.83 | 1094.62 | 2.06 | 2195 | 109 |
700 rows × 12 columns
mean_bc = df2_2[['Downlink Throughput(Kbps)', 'Downlink TCP Retransmission Rate(%)']].mean()[1]
df2_2[['Downlink Throughput(Kbps)', 'Downlink TCP Retransmission Rate(%)']].mean()
Downlink Throughput(Kbps) 2088.457928 Downlink TCP Retransmission Rate(%) 1.917461 dtype: float64
mean_a = df2_3[['Downlink Throughput(Kbps)', 'Downlink TCP Retransmission Rate(%)']].mean()[1]
df2_3[['Downlink Throughput(Kbps)', 'Downlink TCP Retransmission Rate(%)']].mean()
Downlink Throughput(Kbps) 1876.485714 Downlink TCP Retransmission Rate(%) 1.376914 dtype: float64
В виду того, что показатель Downlink Throughput(Kbps) — средняя скорость «к абоненту», считается по всему трафику передачи данных, т.е. основной трафик потребляет просмотр web-страниц и загрузка видео, также мы можем заметить, что рассматриваемое среднее выше в группе A, поэтому будем рассматривать показатель среднего Downlink TCP Retransmission Rate(%) — частота переотправок пакетов «к абоненту».
Рассматривается нулевая гипотеза о равенстве рассматриваемых средних Генеральных совокупностей Альтернативная гипотеза - рассматриваемые средние не равны (Предполагается что среднее группы B < среднее группы A, т.к. больше - хуже)
mean_diff = mean_bc - mean_a
mean_diff
0.5405468037798775
differences = np.zeros((1, 1500))
confidence = 0.95
count = 0
for i in range(0, 1500):
s1 = random.choices(df2_2['Downlink TCP Retransmission Rate(%)'].values, k=1000)
s2 = random.choices(df2_3['Downlink TCP Retransmission Rate(%)'].values, k=1000)
m1 = np.mean(s1)
m2 = np.mean(s2)
n = len(s1)
se1 = st.sem(s1)
se2 = st.sem(s2)
h1 = se1 * st.t._ppf((1+confidence)/2., n-1)
h2 = se2 * st.t._ppf((1+confidence)/2., n-1)
differences[0][i] = m1 - m2
l1, r1, l2, r2 = m1-h1, m1+h1, m2-h2, m2+h2 # Левая и правая граница интервалов
if (l2<l1<r2<r1) or (l1<l2<r2<r1) or (l2<l1<r1<r2) or (l1<l2<r1<r2): #пересечение интервалов
print(l1,r1,l2,r2) # Выводим значения интервалов, если они пересекаются
if (l2<r2<l1<r1):
count += 1 # Считаем число случаев, когда доверительный интервал группы B меньше,
#чем интервал группы A
print(count) # Число случаев, когда интервал группы B левее, чем интервал группы A
1500
((differences - np.mean(differences)) >= mean_diff).sum()
# В скольких случаях значения центрированного вектора превосходит заданную разницу
0
P-value = 0 -> меньше чем любой разумный уровень значимости -> нулевая гипотеза о равенстве средних отклоняется -> Разница есть
df_diff = pd.DataFrame(differences).transpose() # Датафрейм разницы средних для построения графика
df_diff.columns = ['differences']
df_diff
| differences | |
|---|---|
| 0 | 0.50066 |
| 1 | 0.59642 |
| 2 | 0.58746 |
| 3 | 0.53150 |
| 4 | 0.44076 |
| ... | ... |
| 1495 | 0.69052 |
| 1496 | 0.62599 |
| 1497 | 0.48840 |
| 1498 | 0.52523 |
| 1499 | 0.52600 |
1500 rows × 1 columns
fig = px.histogram(df_diff, nbins = 50,
title='Распределение разницы средних для рассматриваемых групп')
fig.show() # Распределение близко к нормальному
На основании произведенных расчетов и тестов можем сделать вывод, что показатель Downlink TCP Retransmission Rate(%) — частота переотправок пакетов «к абоненту», статистически различается (значимо больше у пользователей рассматриваемой группы A (Q2-1,2,3) ГС, чем у пользоваталей, довольных качеством).
Проверяем гипотезу относительно разницы средних показателя Downlink Throughput(Kbps)(средняя скорость «к абоненту») между группами пользоваталей A и B
Группа A - пользователи, ответившие на второй вопрос (Q2) - 3: Плохое качество связи в зданиях, тц и т.д.; Группа B - пользователи, ответившие на второй вопрос (Q2) - 4:Медленный мобильный интернет
Берем наши выборки, делаем по каждой из них бутстреп и проверяем с помощью построения доверительных интервалов, пересекаются ли они, а также генерируем распределние разницы средних.
Рассматривается нулевая гипотеза о равенстве рассматриваемых средних Генеральных совокупностей Альтернативная гипотеза - рассматриваемые средние не равны
# Рассматриваются независимые наблюдения в двух группах
mass = data_Q2[(data_Q2['Q2'] == '3') | (data_Q2['Q2'] == '4')]
indexes = pd.DataFrame(mass['user_id'].value_counts())
indexes = indexes[indexes['user_id'] != 1].index
mass['user_id'] = [np.NaN if elem in indexes else elem for elem in mass['user_id']]
mass = mass.dropna()
mass
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 4 | B | 8 | 3 | 179.18564 | 2590.97 | 325.88 | 7053.81 | 1221.02 | 0.80 | 3218 | 51 |
| 13 | 11 | C | 3 | 3 | 526.08652 | 535.54 | 208.67 | 2621.14 | 2376.50 | 1.46 | 1479 | 88 |
| 16 | 19 | B | 7 | 3 | 811.55618 | 460.32 | 65.20 | 1583.27 | 1587.16 | 1.50 | 1340 | 57 |
| 31 | 50 | C | 2 | 3 | 453.12793 | 3325.86 | 167.74 | 11702.86 | 2455.82 | 0.59 | 1212 | 40 |
| 35 | 53 | B | 6 | 3 | 168.11047 | 2031.20 | 164.31 | 5234.92 | 1665.56 | 0.71 | 1838 | 95 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2705 | 3095 | C | 3 | 3 | 566.73519 | 3477.18 | 124.84 | 5427.74 | 2410.91 | 0.76 | 1188 | 145 |
| 2718 | 3101 | C | 2 | 4 | 248.99905 | 2347.42 | 309.08 | 5001.39 | 1837.79 | 1.64 | 1394 | 83 |
| 2719 | 3102 | B | 8 | 4 | 189.14150 | 2432.18 | 72.80 | 2152.91 | 1410.52 | 0.70 | 2719 | 289 |
| 2727 | 3108 | C | 3 | 4 | 519.96475 | 1045.70 | 44.61 | 4523.66 | 1044.66 | 0.47 | 1468 | 304 |
| 2735 | 3111 | B | 6 | 3 | 827.74515 | 1841.90 | 373.53 | 5675.93 | 2361.88 | 1.21 | 1905 | 202 |
443 rows × 12 columns
# Группа A
df3_2 = mass[(mass['Q2'] == '3')] # Интересующие нас пользователи
# Группа B
df3_3 = mass[(mass['Q2'] == '4')]
df3_3
| user_id | Group | Q1 | Q2 | Total Traffic(MB) | Downlink Throughput(Kbps) | Uplink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Web Page Download Throughput(Kbps) | Downlink TCP Retransmission Rate(%) | Video Streaming xKB Start Delay(ms) | Web Average TCP RTT(ms) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 45 | 67 | C | 3 | 4 | 204.46809 | 1109.97 | 100.50 | 5360.84 | 1671.27 | 0.79 | 1402 | 136 |
| 108 | 129 | C | 1 | 4 | 641.85847 | 4410.52 | 357.93 | 6230.28 | 1877.49 | 1.86 | 1143 | 73 |
| 112 | 134 | B | 7 | 4 | 126.95619 | 3557.73 | 80.84 | 7237.32 | 4717.72 | 0.30 | 895 | 171 |
| 136 | 168 | C | 1 | 4 | 661.11584 | 1057.29 | 144.00 | 5493.31 | 1615.08 | 1.57 | 1346 | 77 |
| 164 | 202 | B | 8 | 4 | 825.33039 | 832.71 | 181.23 | 2164.55 | 929.74 | 3.65 | 2807 | 180 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2691 | 3077 | B | 5 | 4 | 144.43657 | 781.40 | 114.33 | 4721.98 | 2530.44 | 2.07 | 1608 | 118 |
| 2701 | 3091 | C | 2 | 4 | 775.73132 | 420.91 | 67.61 | 1981.25 | 658.33 | 2.31 | 2024 | 266 |
| 2718 | 3101 | C | 2 | 4 | 248.99905 | 2347.42 | 309.08 | 5001.39 | 1837.79 | 1.64 | 1394 | 83 |
| 2719 | 3102 | B | 8 | 4 | 189.14150 | 2432.18 | 72.80 | 2152.91 | 1410.52 | 0.70 | 2719 | 289 |
| 2727 | 3108 | C | 3 | 4 | 519.96475 | 1045.70 | 44.61 | 4523.66 | 1044.66 | 0.47 | 1468 | 304 |
175 rows × 12 columns
mean_bc_2 = df3_2[['Downlink Throughput(Kbps)']].mean()[0]
df3_2[['Downlink Throughput(Kbps)']].mean()
Downlink Throughput(Kbps) 1799.950075 dtype: float64
mean_a_2 = df3_3[['Downlink Throughput(Kbps)']].mean()[0]
df3_3[['Downlink Throughput(Kbps)']].mean()
Downlink Throughput(Kbps) 1690.419371 dtype: float64
mean_diff_2 = mean_bc_2 - mean_a_2
mean_diff_2
109.53070319829408
differences = np.zeros((1, 1500))
confidence = 0.95
count = 0
for i in range(0, 1500):
s1 = random.choices(df3_2['Downlink Throughput(Kbps)'].values, k=1000)
s2 = random.choices(df3_3['Downlink Throughput(Kbps)'].values, k=1000)
m1 = np.mean(s1)
m2 = np.mean(s2)
n = len(s1)
se1 = st.sem(s1)
se2 = st.sem(s2)
h1 = se1 * st.t._ppf((1+confidence)/2., n-1)
h2 = se2 * st.t._ppf((1+confidence)/2., n-1)
differences[0][i] = m1 - m2
l1, r1, l2, r2 = m1-h1, m1+h1, m2-h2, m2+h2 # Левая и правая граница интервалов
if (l1<l2<r1<r2) or (l2<l1<r1<r2) or (l1<l2<r2<r1) or (l2<l1<r2<r1): #пересечение интервалов
count += 1 # Выводим значения интервалов, если они пересекаются
print(count)
1235
(np.abs((differences - np.mean(differences))) >= mean_diff_2).sum() / 1500
# Доля случаев когда центрированная разница больше изначально заданной
0.06933333333333333
Полученное P-value больше чем P-value = 0.05 при заданном уровне значимости -> нет оснований отклонить нулевую гипотезу о равенстве средних
df_diff = pd.DataFrame(differences - np.mean(differences)).transpose() # Датафрейм разницы средних для построения графика
df_diff.columns = ['differences']
df_diff
| differences | |
|---|---|
| 0 | -38.437859 |
| 1 | -18.406019 |
| 2 | 90.687391 |
| 3 | -25.833689 |
| 4 | -72.946259 |
| ... | ... |
| 1495 | 104.757731 |
| 1496 | -22.808099 |
| 1497 | 81.089211 |
| 1498 | -2.017399 |
| 1499 | 76.668221 |
1500 rows × 1 columns
fig = px.histogram(df_diff, nbins = 50,
title='Распределение разницы средних для рассматриваемых групп')
fig.show() # Распределение близко к нормальному
mass.groupby(['Q2'])[['Downlink Throughput(Kbps)']] \
.agg(['count', 'mean', 'median']).round(2) \
.style.apply(lambda x: ['background: lightgreen' if x.name else '' for i in x], axis=1)
| Downlink Throughput(Kbps) | |||
|---|---|---|---|
| count | mean | median | |
| Q2 | |||
| 3 | 268 | 1799.950000 | 1477.220000 |
| 4 | 175 | 1690.420000 | 1218.060000 |
data_Q1_Out.groupby(['Group'])[['Downlink Throughput(Kbps)']] \
.agg(['count', 'mean', 'median']).round(2) \
.style.apply(lambda x: ['background: orange' if x.name == 'A' else '' for i in x], axis=1)
| Downlink Throughput(Kbps) | |||
|---|---|---|---|
| count | mean | median | |
| Group | |||
| A | 700 | 1876.490000 | 1519.740000 |
| B | 547 | 1842.240000 | 1366.610000 |
| C | 734 | 1662.220000 | 1293.520000 |
На основании произведенных расчетов и тестов можем сделать вывод, что показатель Downlink Throughput(Kbps)(средняя скорость «к абоненту»), статистически не различается и одинаково мал у ГС пользователей ответивших на второй вопрос (Q2) - 3: Плохое качество связи в зданиях, тц и т.д. и пользователей, ответивших на второй вопрос (Q2) - 4: Медленный мобильный интернет
Следовательно, следует обратить внимание на данный показатель качества связи, т.к. минимум 2 группы пользователей, недовольные разными аспектами связи, имеют одинаково низкие значения
Рассмотрим показатели скорости загрузки потокового видео и задержки старта воспроизведения для пользователей с медленной загрузкой видео
data_Q2.groupby(['Q2'])[['Downlink Throughput(Kbps)',
'Video Streaming Download Throughput(Kbps)',
'Video Streaming xKB Start Delay(ms)']] \
.agg(['count', 'mean', 'median']).sort_values(by='Q2') \
.iloc[:, [0, 1, 2, 4, 5, 7, 8]] \
.style.apply(lambda x: ['background: lightblue' if x.name == '5' else '' for i in x], axis=1)
| Downlink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Video Streaming xKB Start Delay(ms) | |||||
|---|---|---|---|---|---|---|---|
| count | mean | median | mean | median | mean | median | |
| Q2 | |||||||
| 1 | 403 | 1787.284045 | 1361.300000 | 5045.347916 | 4576.390000 | 1817.253102 | 1662.000000 |
| 2 | 124 | 1654.466774 | 1095.545000 | 4793.183790 | 4050.375000 | 1847.862903 | 1709.500000 |
| 3 | 480 | 1728.353542 | 1314.740000 | 4817.769083 | 4252.065000 | 1809.033333 | 1664.500000 |
| 4 | 387 | 1661.618786 | 1155.320000 | 4482.688837 | 3915.890000 | 1902.981912 | 1743.000000 |
| 5 | 136 | 1447.946029 | 1108.190000 | 3919.861838 | 3287.100000 | 1929.757353 | 1743.500000 |
| 6 | 452 | 1684.155686 | 1265.225000 | 5047.898628 | 4349.455000 | 1796.794248 | 1671.000000 |
| 7 | 54 | 1753.447778 | 1543.905000 | 4808.978148 | 4223.850000 | 1817.148148 | 1700.500000 |
data_Q1_Out.groupby(['Group'])[['Downlink Throughput(Kbps)',
'Video Streaming Download Throughput(Kbps)',
'Video Streaming xKB Start Delay(ms)']] \
.agg(['count', 'mean', 'median']).iloc[:, [0, 1, 2, 4, 5, 7, 8]].round(2) \
.style.apply(lambda x: ['background: orange' if x.name == 'A' else '' for i in x], axis=1)
| Downlink Throughput(Kbps) | Video Streaming Download Throughput(Kbps) | Video Streaming xKB Start Delay(ms) | |||||
|---|---|---|---|---|---|---|---|
| count | mean | median | mean | median | mean | median | |
| Group | |||||||
| A | 700 | 1876.490000 | 1519.740000 | 5371.520000 | 4821.220000 | 1696.580000 | 1572.500000 |
| B | 547 | 1842.240000 | 1366.610000 | 5260.610000 | 4623.440000 | 1768.550000 | 1655.000000 |
| C | 734 | 1662.220000 | 1293.520000 | 4708.800000 | 4109.820000 | 1855.180000 | 1694.000000 |
# Наблюдения в выборках группы A и ответивших на второй вопрос 5 независимы
data_Q2['Video Streaming Download Throughput(Kbps)'][(data_Q2['Q1'] == 'A') |
(data_Q2['Q2'] == '5')].duplicated().sum()
0
fig = px.scatter(data_Q1_Out, x='Video Streaming xKB Start Delay(ms)',
y='Video Streaming Download Throughput(Kbps)',
color='Group',
title='Зависимость скорости загрузки видео от задержки начала воспроизведения')
fig.show()
fig = px.scatter(data_Q1_Out, x='Downlink Throughput(Kbps)',
y='Video Streaming Download Throughput(Kbps)',
color='Group',
title='Зависимость скорости загрузки видео от скорости "к абоненту"')
fig.show()
fig = px.histogram(data_Q1_Out, x='Video Streaming Download Throughput(Kbps)',
title='Распределение скорости загрузки потокового видео')
fig.show()
Непараметрические критерии используются для следующих переменных:
- для количественных переменных, распределение которых не подчиняется нормальному закону распределения;
Непараметрические критерии могут применяться и в случае нормального распределения. В этом случае они будут иметь только 95%-ую эффективность по сравнению с параметрическими тестами.
Существует большое количество непараметрических тестов, которые можно разделить на три группы:
- критерии для независимых выборок (U критерий Манна-Уитни (при сумме размеров выборок >60 U-статистика аппроксимируется нормальным распределением), критерий Колмогорова-Смирнова для двух выборок, критерий Вальда-Вольфовица, критерий Мозеса, непараметрический дисперсионный анализ Крускала-Уоллиса, медианный критерий, критерий Джонкхира-Терпстры и др.)